
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/fs.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/rwsem.h>
#include <linux/dma-mapping.h>
#include <linux/pagemap.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <asm/div64.h>
#include <linux/delay.h>
#include "riffa_driver.h"
#include "circ_queue.h"


dma_addr_t kbuff_hwaddr;
static void *kbuff;
#define BUF_SIZE (8*PAGE_SIZE)

MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("PCIe driver for RIFFA, Linux (2.6.27+)");
MODULE_AUTHOR("Matt Jacobsen, Patrick Lai");

#ifndef __devinit
#define __devinit
#define __devexit
#define __devexit_p
#endif

#define CHNL_REG(c, o) ((c << 4) + o)
#if !defined(__LP64__) && !defined(_LP64)
#define BUILD_32 1
#endif

#define CHNL_FLAG_BUSY 0

struct sg_mapping
{
	struct page **pages;
	struct scatterlist *sgl;
	enum dma_data_direction direction;
	int num_sg;
	unsigned long num_pages;
	unsigned long long length;
	unsigned long long overflow;
};

struct chnl_dir
{
	volatile unsigned long flags;
	wait_queue_head_t waitq;
	struct circ_queue *msgs;
	void *buf_addr;
	dma_addr_t buf_hw_addr;
	struct sg_mapping *sg_map_0;
	struct sg_mapping *sg_map_1;
};

struct fpga_state
{
	struct pci_dev *dev;
	unsigned long long irq;
	void __iomem *bar0;
	unsigned long long bar0_addr;
	unsigned long long bar0_len;
	unsigned long long bar0_flags;
	atomic_t intr_disabled;
	void *spill_buf_addr;
	dma_addr_t spill_buf_hw_addr;
	int num_sg;
	int sg_buf_size;
	int id;
	char name[16];
	int vendor_id;
	int device_id;
	int num_chnls;
	struct chnl_dir **recv;
	struct chnl_dir **send;
};

// Global variables (to this file only)
static struct class *mymodule_class;
static dev_t devt;
static atomic_t used_fpgas[NUM_FPGAS];
static struct fpga_state *fpgas[NUM_FPGAS];

///////////////////////////////////////////////////////
// MEMORY ALLOCATION & HELPER FUNCTIONS
///////////////////////////////////////////////////////

/** 
 * Returns the value at the specified address.
 */
static inline unsigned int read_reg(struct fpga_state *sc, int offset)
{
	return readl(sc->bar0 + (offset << 2));
}

/** 
 * Writes the value to the specified address.
 */
static inline void write_reg(struct fpga_state *sc, int offset, unsigned int val)
{
	writel(val, sc->bar0 + (offset << 2));
}

#ifdef BUILD_32
/**
 * Needed for 32 bit OS because dma_map_sg macro eventually does some 64 bit
 * division.
 */
unsigned long long __udivdi3(unsigned long long num, unsigned long long den)
{
	do_div(num, den);
	return num;
}
#endif

// These are not defined in the 2.x.y kernels, so just define them
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)
#define PCI_EXP_DEVCTL2_IDO_REQ_EN 0x100
#define PCI_EXP_DEVCTL2_IDO_CMP_EN 0x200
#else
/** 
 * These are badly named in pre-3.6.11 kernel versions.  We COULD do the same
 * check as above, however (annoyingly) linux for tegra (based on post-3.6.11)
 * picked up the header file from some pre-3.6.11 version, so we'll just make
 * our code ugly and handle the check here:
 */
#ifndef PCI_EXP_DEVCTL2_IDO_REQ_EN
#define PCI_EXP_DEVCTL2_IDO_REQ_EN PCI_EXP_IDO_REQ_EN
#endif
#ifndef PCI_EXP_DEVCTL2_IDO_CMP_EN
#define PCI_EXP_DEVCTL2_IDO_CMP_EN PCI_EXP_IDO_CMP_EN
#endif
#endif

#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 6, 11)
/**
 * Code used to set ETB and RCB, but not available before 3.0, or incorrectly
 * defined before 3.7. As it is peppered throughout the clean up code, it's just
 * easier to copy the declarations (not verbatim) here than a bunch of conditionals
 * everywhere else.
 */

int pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *val)
{
	int ret;

	*val = 0;
	if (pos & 1)
		return -EINVAL;

	ret = pci_read_config_word(dev, pci_pcie_cap(dev) + pos, val);
	/*
	 * Reset *val to 0 if pci_read_config_word() fails, it may
	 * have been written as 0xFFFF if hardware error happens
	 * during pci_read_config_word().
	 */
	if (ret)
		*val = 0;
	return ret;
}

int pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *val)
{
	int ret;

	*val = 0;
	if (pos & 3)
		return -EINVAL;

	ret = pci_read_config_dword(dev, pci_pcie_cap(dev) + pos, val);

	if (ret)
		*val = 0;
	return ret;
}

int pcie_capability_write_word(struct pci_dev *dev, int pos, u16 val)
{
	if (pos & 1)
		return -EINVAL;

	return pci_write_config_word(dev, pci_pcie_cap(dev) + pos, val);
}

int pcie_capability_write_dword(struct pci_dev *dev, int pos, u32 val)
{
	if (pos & 3)
		return -EINVAL;

	return pci_write_config_dword(dev, pci_pcie_cap(dev) + pos, val);
}
#endif


static inline int list_fpgas(fpga_info_list *list)
{
	int i;
	int num_fpgas = 0;
	struct fpga_state *sc;

	for (i = 0; i < NUM_FPGAS; ++i)
	{
		if (atomic_read(&used_fpgas[i]))
		{
			sc = fpgas[i];
			list->id[num_fpgas] = sc->id;
			list->num_chnls[num_fpgas] = sc->num_chnls;
			list->vendor_id[num_fpgas] = sc->vendor_id;
			list->device_id[num_fpgas] = sc->device_id;
			memcpy(list->name[num_fpgas], sc->name, 16 * sizeof(char));
			num_fpgas++;
		}
	}
	// Zero out the rest
	for (i = num_fpgas; i < NUM_FPGAS; ++i)
	{
		list->id[i] = -1;
		list->num_chnls[i] = 0;
		list->vendor_id[i] = 0;
		list->device_id[i] = 0;
		memset(list->name[i], 0, 16 * sizeof(char));
	}
	list->num_fpgas = num_fpgas;

	return 0;
}

/**
 * Resets the driver for the specified FPGA. The fpga_state struct for all 
 * channels will be reset as will the FPGA itself. 
 */
static inline void reset(int id)
{
	int i;
	unsigned int dummy0;
	unsigned int dummy1;
	struct fpga_state *sc;

	if (atomic_read(&used_fpgas[id]))
	{
		sc = fpgas[id];
		// Disable interrupts
		atomic_set(&sc->intr_disabled, 1);
		// Reset the FPGA
		read_reg(sc, INFO_REG_OFF);

		// Reset all the channels
		for (i = 0; i < sc->num_chnls; ++i)
		{
			while (!pop_circ_queue(sc->send[i]->msgs, &dummy0, &dummy1))
				;
			while (!pop_circ_queue(sc->recv[i]->msgs, &dummy0, &dummy1))
				;
			wake_up(&sc->send[i]->waitq);
			wake_up(&sc->recv[i]->waitq);
			clear_bit(CHNL_FLAG_BUSY, &sc->send[i]->flags);
			clear_bit(CHNL_FLAG_BUSY, &sc->recv[i]->flags);
		}
		// Enable interrupts
		atomic_set(&sc->intr_disabled, 0);
	}
}

/**
 * Main entry point for reading and writing on the device. Return value depends 
 * on ioctlnum and expected behavior. See code for details.
 */

#define GK_VAL_DMANUM    0X00000001
#define GK_VAL_ADD0      (0X00000004*4<< 8)
#define GK_VAL_DIR       (0X00000001 << 25)
#define GK_VAL_ACK       (0X00000001 << 26)
#define GK_VAL_DMAENB    (0X00000001 << 24)

#define GK_VAL_CLEARINT    (0X00000001 << 24)

#define GK_BAR0_OFF_0 0X00
#define GK_BAR0_OFF_1 0X01
#define GK_BAR0_OFF_2 0X02
#define GK_BAR0_OFF_3 0X03
#define GK_BAR0_OFF_4 0X04
#define GK_BAR0_OFF_5 0X05
#define GK_BAR0_OFF_6 0X06



static inline void gk_cfg_set(struct fpga_state *sc, fpga_gk_config temp)
{
	unsigned int val;
//	unsigned int i;

	printk("riffa: 1gk_cfg.damSum=%d\n", temp.damSum);
	printk("riffa: 11gk_cfg.damLen=%d\n", temp.damLen);

	    val=read_reg(sc,GK_BAR0_OFF_0);
    printk("riffa: 000--------------------------------\n");
    printk("riffa: kbuff_hwaddr=%lx\n", (long unsigned int) kbuff_hwaddr);
	//write_reg(sc, GK_BAR0_OFF_2,1);					   //reset fpga
    val=read_reg(sc,GK_BAR0_OFF_0);
    printk("riffa: 000--------------------------------\n");
	write_reg(sc, GK_BAR0_OFF_1, GK_VAL_CLEARINT);	

	printk("riffa: 111--------------------------------x\n");
	write_reg(sc, GK_BAR0_OFF_4, kbuff_hwaddr);//本次DMA传输的主机地址
	write_reg(sc, GK_BAR0_OFF_5, 0);                       //本次DMA传输的FPGA端地址
	write_reg(sc, GK_BAR0_OFF_6, 512);                     //本次DMA传输长度，32bits单位
	
	val = 0;
	val = GK_VAL_DMANUM | GK_VAL_ADD0 | GK_VAL_DIR | GK_VAL_ACK | GK_VAL_DMAENB;
	write_reg(sc, GK_BAR0_OFF_0, val);
	
	val=read_reg(sc,GK_BAR0_OFF_0);
	printk("riffa: GK_BAR0_OFF_0=%x\n", val);
	val=read_reg(sc,GK_BAR0_OFF_1);
	printk("riffa: GK_BAR0_OFF_1=%x\n", val);
	val=read_reg(sc,GK_BAR0_OFF_2);
	printk("riffa: GK_BAR0_OFF_2=%x\n", val);
	val=read_reg(sc,GK_BAR0_OFF_3);
	printk("riffa: GK_BAR0_OFF_3=%x\n", val);
	val=read_reg(sc,GK_BAR0_OFF_4);
	printk("riffa: GK_BAR0_OFF_4=%x\n", val);
	val=read_reg(sc,GK_BAR0_OFF_5);
	printk("riffa: GK_BAR0_OFF_5=%x\n", val);
	val=read_reg(sc,GK_BAR0_OFF_6);
	printk("riffa: GK_BAR0_OFF_6=%x\n", val);
    printk("riffa: 222---------------------------------x\n");
}
static long fpga_ioctl(struct file *filp, unsigned int ioctlnum, unsigned long ioctlparam)
{
	int rc;
	fpga_chnl_io io;
	fpga_info_list list;
	fpga_gk_config gk_cfg;

	switch (ioctlnum)
	{
	case IOCTL_CFG_RECV:

		printk("riffa:-------enter fpga_ioctl---------------------\n");
		if ((rc = copy_from_user(&gk_cfg, (void *)ioctlparam, sizeof(fpga_gk_config))))
		{
			printk("riffa: cannot read ioctl user parameter.\n");
			return rc;
		}

		gk_cfg_set(fpgas[0], gk_cfg);
		//return chnl_recv_wrapcheck(fpgas[0], gk_cfg.chnl, gk_cfg.data, gk_cfg.len, gk_cfg.timeout);
		return 0;
	case IOCTL_SEND:

		return 0;

	case IOCTL_RECV:
		if ((rc = copy_from_user(&io, (void *)ioctlparam, sizeof(fpga_chnl_io))))
		{
			printk(KERN_ERR "riffa: cannot read ioctl user parameter.\n");
			return rc;
		}
		if (io.id < 0 || io.id >= NUM_FPGAS || !atomic_read(&used_fpgas[io.id]))
			return 0;
		//return chnl_recv_wrapcheck(fpgas[io.id], io.chnl, io.data, io.len, io.timeout);
		return 0;
	case IOCTL_LIST:
		list_fpgas(&list);
		if ((rc = copy_to_user((void *)ioctlparam, &list, sizeof(fpga_info_list))))
			printk(KERN_ERR "riffa: cannot write ioctl user parameter.\n");
		return rc;
	case IOCTL_RESET:
		reset((int)ioctlparam);
		break;
	default:
		return -ENOTTY;
		break;
	}
	return 0;
}
static inline void process_intr_vector(struct fpga_state *sc, int off,
									   unsigned int vect)
{
	unsigned int len;
	int recv;
	int chnl;

	//-----------------------------------------
    if (vect ==1)
	{
			recv = 1;
			// Read the transferred amount.
			len = 512;
			// Notify the thread.
			if (push_circ_queue(sc->recv[chnl]->msgs, EVENT_TXN_DONE, len))
			{
				printk(KERN_ERR "riffa: fpga:%d chnl:%d, recv txn done msg queue full\n", sc->id, chnl);
			}
			printk(KERN_INFO "riffa: fpga:%d chnl:%d, recv txn done\n", sc->id, chnl);
	}
	
	if (recv)
			wake_up(&sc->recv[chnl]->waitq);
	return ;
	//----------------

}
static irqreturn_t intrpt_handler(int irq, void *dev_id)
{
	unsigned int vect0;
	unsigned int vect1;
	struct fpga_state *sc;
    int value,i;
	sc = (struct fpga_state *)dev_id;
	vect0 = 0;
	vect1 = 0;


    printk("riffa: enter intrpt_handler----------------11\n");
	if (sc == NULL)
	{
		printk(KERN_ERR "riffa: invalid fpga_state pointer\n");
		return IRQ_HANDLED;
	}
	
	printk("recv buf_addr =%lx;\n", (long unsigned int)sc->recv[0]->buf_addr);
	printk("recv hw_addr =%lx;\n", (long unsigned int)sc->recv[0]->buf_hw_addr);

	for(i=0;i<128;i++)
	{
		value =*(int *)(sc->recv[0]->buf_addr+i*4); 
		printk("buf_hw_addr[0] value =%x;\n",value);
	}

	if (!atomic_read(&sc->intr_disabled))
	{
		// Read the interrupt vector(s):
		printk("riffa: enter intrpt_handler----------------22\n");
		vect0 = 1;
		process_intr_vector(sc, 0, vect0);
	}


	return IRQ_HANDLED;
}
static int __devinit fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
	int error;
	struct fpga_state *sc;

	printk("riffa: enter fpga_probe\n");
	// Setup the PCIe device.
	error = pci_enable_device(dev);
	if (error < 0)
	{
		printk(KERN_ERR "riffa: pci_enable_device returned %d\n", error);
		return (-ENODEV);
	}
	// Enable bus master
	pci_set_master(dev);
	// Set the mask size
	error = pci_set_dma_mask(dev, DMA_BIT_MASK(64));
	if (!error)
	{
		error = pci_set_consistent_dma_mask(dev, DMA_BIT_MASK(64));
		printk("riffa: set 64 bit DMA mode\n");
	}
	if (error)
	{
		printk(KERN_ERR "riffa: cannot set 64 bit DMA mode\n");
		pci_disable_device(dev);
		return error;
	}
	// Allocate device structure.
	sc = kzalloc(sizeof(*sc), GFP_KERNEL);
	printk("riffa: sc len =%lu;\n", sizeof(*sc));

	if (sc == NULL)
	{
		printk(KERN_ERR "riffa: not enough memory to allocate sc\n");
		pci_disable_device(dev);
		return (-ENOMEM);
	}
	atomic_set(&sc->intr_disabled, 0);
	snprintf(sc->name, sizeof(sc->name), "%s%d", pci_name(dev), 0);
	sc->vendor_id = dev->vendor;
	sc->device_id = dev->device;
	printk(KERN_INFO "riffa: found FPGA with name: %s\n", sc->name);
	printk(KERN_INFO "riffa: vendor id: 0x%04X\n", sc->vendor_id);
	printk(KERN_INFO "riffa: device id: 0x%04X\n", sc->device_id);

	// Setup the BAR memory regions
	error = pci_request_regions(dev, sc->name);
	if (error < 0)
	{
		printk(KERN_ERR "riffa: pci_request_regions returned error: %d\n", error);
		pci_disable_device(dev);
		kfree(sc);
		return (-ENODEV);
	}

	// PCI BAR 0
	sc->bar0_addr = pci_resource_start(dev, 0);
	sc->bar0_len = pci_resource_len(dev, 0);
	sc->bar0_flags = pci_resource_flags(dev, 0);

	printk(KERN_INFO "riffa: BAR 0 address: %lx\n", (long unsigned int)sc->bar0_addr);
	printk(KERN_INFO "riffa: BAR 0 length: %lld bytes\n", sc->bar0_len);
	printk(KERN_INFO "riffa: BAR 0 flags: %lld bytes\n", sc->bar0_flags);
	if (sc->bar0_len != BAR0_LEN)
	{
		printk(KERN_ERR "riffa: BAR 0 incorrect length\n");
		pci_release_regions(dev);
		pci_disable_device(dev);
		kfree(sc);
		return (-ENODEV);
	}
	sc->bar0 = ioremap(sc->bar0_addr, sc->bar0_len);
	printk(KERN_INFO "riffa: sc->bar0 : %lx\n", (long unsigned int)sc->bar0);
	if (!sc->bar0)
	{
		printk(KERN_ERR "riffa: could not ioremap BAR 0\n");
		pci_release_regions(dev);
		pci_disable_device(dev);
		kfree(sc);
		return (-ENODEV);
	}

	// Setup MSI interrupts
	error = pci_enable_msi(dev);
	if (error != 0)
	{
		printk(KERN_ERR "riffa: pci_enable_msi returned error: %d\n", error);
		iounmap(sc->bar0);
		pci_release_regions(dev);
		pci_disable_device(dev);
		kfree(sc);
		return error;
	}

	// Request an interrupt
	error = request_irq(dev->irq, intrpt_handler, IRQF_SHARED, sc->name, sc);
	if (error != 0)
	{
		printk(KERN_ERR "riffa: request_irq(%d) returned error: %d\n", dev->irq, error);
		pci_disable_msi(dev);
		iounmap(sc->bar0);
		pci_release_regions(dev);
		pci_disable_device(dev);
		kfree(sc);
		return error;
	}
	sc->irq = dev->irq;
	printk(KERN_INFO "riffa: MSI setup on irq＝ %d\n",dev->irq);
	printk(KERN_INFO "riffa: dev->msi_enabled＝　%d\n",dev->msi_enabled);
	//-------------------------------------------------------------

	kbuff= pci_alloc_consistent(dev, BUF_SIZE, &kbuff_hwaddr);

	printk("riffa: kbuff =%lx;\n", (long unsigned int)kbuff);
	printk("riffa: kbuff_hwaddr =%lx;\n",  (long unsigned int)kbuff_hwaddr);

	return 0;
}

static void __devexit fpga_remove(struct pci_dev *dev)
{
	int i;
	u32 result;
	struct fpga_state *sc;

	pcie_capability_read_dword(dev, PCI_EXP_DEVCTL, &result);
	pcie_capability_write_dword(dev, PCI_EXP_DEVCTL, result & ~(PCI_EXP_DEVCTL_EXT_TAG | PCI_EXP_DEVCTL_RELAX_EN));

	pcie_capability_read_dword(dev, PCI_EXP_DEVCTL2, &result);
	pcie_capability_write_dword(dev, PCI_EXP_DEVCTL2, result & ~(PCI_EXP_DEVCTL2_IDO_REQ_EN | PCI_EXP_DEVCTL2_IDO_CMP_EN));

	pcie_capability_read_dword(dev, PCI_EXP_DEVCTL, &result);
	pcie_capability_write_dword(dev, PCI_EXP_LNKCTL, result & (~PCI_EXP_LNKCTL_RCB));

	if ((sc = (struct fpga_state *)pci_get_drvdata(dev)) != NULL)
	{
		// Free structs, memory regions, etc.
		atomic_set(&used_fpgas[sc->id], 0);
		for (i = 0; i < sc->num_chnls; ++i)
		{
			pci_free_consistent(dev, sc->sg_buf_size, sc->send[i]->buf_addr,
								(dma_addr_t)sc->send[i]->buf_hw_addr);
			pci_free_consistent(dev, sc->sg_buf_size, sc->recv[i]->buf_addr,
								(dma_addr_t)sc->recv[i]->buf_hw_addr);
			free_circ_queue(sc->send[i]->msgs);
			free_circ_queue(sc->recv[i]->msgs);
			kfree(sc->send[i]);
			kfree(sc->recv[i]);
		}
		kfree(sc->recv);
		kfree(sc->send);
		pci_free_consistent(dev, SPILL_BUF_SIZE, sc->spill_buf_addr,
							(dma_addr_t)sc->spill_buf_hw_addr);
		free_irq(dev->irq, sc);
		iounmap(sc->bar0);
		kfree(sc);
	}
	pci_disable_msi(dev);
	pci_release_regions(dev);
	pci_disable_device(dev);
	pci_set_drvdata(dev, NULL);
}

static DEFINE_PCI_DEVICE_TABLE(fpga_ids) = {
	{PCI_DEVICE(VENDOR_ID0, PCI_ANY_ID)},
	//{PCI_DEVICE(VENDOR_ID1, PCI_ANY_ID)},
	{0},
};

MODULE_DEVICE_TABLE(pci, fpga_ids);
static struct pci_driver fpga_driver = {
	.name = DEVICE_NAME,
	.id_table = fpga_ids,
	.probe = fpga_probe,
	.remove = __devexit_p(fpga_remove),
};
static int riffa_drv_open(struct inode *inode, struct file *file)
{
	struct mm_struct *mm = current->mm;
	printk("riffa: riffa_drv_open\n");
 	printk("client: %s (%d)\n", current->comm, current->pid);
	printk("code  section: [0x%lx   0x%lx]\n", mm->start_code, mm->end_code);
	printk("data  section: [0x%lx   0x%lx]\n", mm->start_data, mm->end_data);
	printk("brk   section: s: 0x%lx, c: 0x%lx\n", mm->start_brk, mm->brk);
	printk("mmap  section: s: 0x%lx\n", mm->mmap_base);
	printk("stack section: s: 0x%lx\n", mm->start_stack);
	printk("arg   section: [0x%lx   0x%lx]\n", mm->arg_start, mm->arg_end);
	printk("env   section: [0x%lx   0x%lx]\n", mm->env_start, mm->env_end);
	//填写产品的逻辑
	return 0;
}

int riffa_drv_close(struct inode *inode, struct file *file)
{
	printk("riffa: riffa_drv_close\n");
	//填写产品的逻辑
	return 0;
}
static int riffa_drv_mmap(struct file *file, struct vm_area_struct *vma)
{

    unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
    unsigned long pfn_start = (virt_to_phys(kbuff) >> PAGE_SHIFT) + vma->vm_pgoff;
    unsigned long virt_start = (unsigned long)kbuff + offset;
    unsigned long size = vma->vm_end - vma->vm_start;
    int ret = 0;

    unsigned long pfn_start_test1 = (virt_to_phys(kbuff));
    unsigned long pfn_start_test2 = (kbuff_hwaddr);
	unsigned long pfn_start_test3 = ((virt_to_phys(kbuff) >> PAGE_SHIFT) );
	
	printk("riffa: pfn_start_test1=%lx\n",pfn_start_test1);
	printk("riffa: pfn_start_test2=%lx\n",pfn_start_test2);
	printk("riffa: pfn_start_test3=%lx\n",pfn_start_test3);

	printk("riffa: riffa_drv_mmap\n");
	printk("riffa: riffa_drv_mmap　PAGE_SHIFT=%d\n",PAGE_SHIFT);
    printk("phy: 0x%lx, offset: 0x%lx, size: 0x%lx\n", pfn_start << PAGE_SHIFT, offset, size);

    ret = remap_pfn_range(vma, vma->vm_start, pfn_start, size, vma->vm_page_prot);
    if (ret)
        printk("%s: remap_pfn_range failed at [0x%lx  0x%lx]\n",
            __func__, vma->vm_start, vma->vm_end);
    else
        printk("%s: map 0x%lx to 0x%lx, size: 0x%lx\n", __func__, virt_start,
            vma->vm_start, size);

    return ret;
}
static const struct file_operations fpga_fops = {
	.owner = THIS_MODULE,
	.open=riffa_drv_open,
	.release=riffa_drv_close,
	.mmap=riffa_drv_mmap,
	.unlocked_ioctl=fpga_ioctl,
};

/**
 * Called to initialize the PCI device. 
 */

static int __init fpga_init(void)
{
	int i;
	int error;

	printk("riffa init: MAJOR_NUM=%d;DEVICE_NAME=%s\n", MAJOR_NUM, DEVICE_NAME);

	for (i = 0; i < NUM_FPGAS; i++)
		atomic_set(&used_fpgas[i], 0);

	error = pci_register_driver(&fpga_driver);
	if (error != 0)
	{
		printk(KERN_ERR "riffa: pci_module_register returned %d\n", error);
		return (error);
	}

	error = register_chrdev(MAJOR_NUM, DEVICE_NAME, &fpga_fops);
	if (error < 0)
	{
		printk(KERN_ERR "riffa: register_chrdev returned %d\n", error);
		return (error);
	}
	mymodule_class = class_create(THIS_MODULE, DEVICE_NAME);
	if (IS_ERR(mymodule_class))
	{
		error = PTR_ERR(mymodule_class);
		printk(KERN_ERR "riffa: class_create() returned %d\n", error);
		return (error);
	}
	devt = MKDEV(MAJOR_NUM, 0);
	device_create(mymodule_class, NULL, devt, "%s", DEVICE_NAME);

	return 0;
}

/**
 * Called to destroy the PCI device.
 */
static void __exit fpga_exit(void)
{
	device_destroy(mymodule_class, devt);
	class_destroy(mymodule_class);
	pci_unregister_driver(&fpga_driver);
	unregister_chrdev(MAJOR_NUM, DEVICE_NAME);
}

module_init(fpga_init);
module_exit(fpga_exit);
